package ca.usherbrooke.domus.sipnmove2.model.communication.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.HashSet;
import java.util.Set;

import ca.usherbrooke.domus.sipnmove2.model.communication.Communication;
import ca.usherbrooke.domus.sipnmove2.model.communication.CommunicationListener;

public abstract class AbstractSocketCommunication implements Communication {

	/**
	 * Socket thread
	 */
	private Thread socketThread;

	/**
	 * Socket
	 */
	protected Socket socket;

	/**
	 * Output buffer
	 */
	protected PrintWriter outputBuffer;

	/**
	 * Input buffer
	 */
	protected BufferedReader inputBuffer;

	/**
	 * Input buffer
	 */
	private Set<CommunicationListener> communicationListeners;

	/**
	 * Default constructor
	 */
	public AbstractSocketCommunication()
	{
		this.communicationListeners = new HashSet<CommunicationListener>();
	}

	@Override
	public void addCommunicationListener(CommunicationListener communicationListener) {
		communicationListeners.add(communicationListener);
	}

	@Override
	public void sendMessage(String message) {
		outputBuffer.println(message);
		notifyMessageSent(message);
	}

	@Override
	public void terminate() {
		socketThread = null;
	}

	/**
	 * Start the socket thread
	 */
	protected void startThread()
	{

		if(socketThread == null)
		{
			socketThread = new Thread() {
	
				public void run() {
					String message;
					try {
	
						// Loop until thread is deleted
						while (Thread.currentThread() == socketThread) {
							message = inputBuffer.readLine();
	
							if (message != null)
								notifyMessageReceived(message);
						}
	
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
	
			};
		}

		socketThread.start();
	}
	
	/**
	 * Stop the socket thread
	 */
	protected void stopThread()
	{
		socketThread = null;
	}
	
	/**
	 * Notify listeners of a new message received
	 * @param message
	 */
	private void notifyMessageReceived(String message) {
		for(CommunicationListener communicationListener : communicationListeners)
		{
			communicationListener.processMessageReceived(message);
		}
	}

	/**
	 * Notify listeners of a new message sent
	 * @param message
	 */
	private void notifyMessageSent(String message) {
		for(CommunicationListener communicationListener : communicationListeners)
		{
			communicationListener.processMessageSent(message);
		}
	}
	
}
